package com.cloudfast.oauth.granter;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import com.cloudfast.context.error.CloudException;
import com.cloudfast.context.error.ErrorCode;
import com.cloudfast.redis.CloudRedisTemplate;

/**
 * 短信验证码登入
 *
 * @author liuyw
 * @date 2022年8月29日
 */
public class SmsTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "sms";

    private UserDetailsService userDetailsService;

    private CloudRedisTemplate redisTemplate;

    public SmsTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
                           ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory,
                           CloudRedisTemplate redisTemplate, UserDetailsService userDetailsService) {
        this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.redisTemplate = redisTemplate;
        this.userDetailsService = userDetailsService;
    }

    protected SmsTokenGranter(AuthenticationManager authenticationManager,
                              AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                              OAuth2RequestFactory requestFactory, String grantType) {
        super(tokenServices, clientDetailsService, requestFactory, grantType);
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());

        String phoneNumber = parameters.get("phone");

        String smsCode = parameters.get("sms_code");
        String smsPhoneCode = redisTemplate.get(phoneNumber) == null ? "" : redisTemplate.get(phoneNumber).toString();

        /**
         * 上传的验证码
         */
        if (StringUtils.isEmpty(smsCode)) {
            throw new CloudException(ErrorCode.NO_SMS_CODE);
        }

        try {
            // 查询用户及查询信息
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(phoneNumber);
            if (userDetails != null) {
                /**
                 * redis 中的验证码
                 */
                if (StringUtils.isEmpty(smsPhoneCode)) {
                    throw new CloudException(ErrorCode.SMS_CODE_ERROR);
                }

                /**
                 * 对比验证码
                 */
                if (smsCode.equals(smsPhoneCode)) {

                    Authentication userAuth = new UsernamePasswordAuthenticationToken(userDetails,
                            userDetails.getPassword(), userDetails.getAuthorities());
                    ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

                    OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
                    return new OAuth2Authentication(storedOAuth2Request, userAuth);
                }
                throw new CloudException(ErrorCode.SMS_CODE_ERROR);

            }
        } catch (CloudException e) {
            if (e.getErrorCode() == ErrorCode.USERNAME_PASSWORD_ERROR) {
                throw new CloudException(ErrorCode.NO_PHONE_NUM);
            }
            throw new CloudException(e.getErrorCode());
        }

        throw new CloudException(ErrorCode.NO_PHONE_NUM);

    }

}
